//{include("manager.asl")}
//{include("contractor.asl")}
// Agent manager in project COMP667-Proj

/* Initial beliefs and rules */
last_user_contract_id(0).
last_host_contract_id(0).
plays(host,_hostname).
user_count(0).

plays(user1,_username).
plays(user2,_username).

+ontology(target_ontology,O):true
<-!findhost(O).
 


//+!buildgame(Ontology):true
//<-!findhost(Ontology);
//.print("finished findhost");

//.at("now +5 seconds", { +!finduser });

//.print("finished find user1");
//.at("now +10 seconds", { +!finduser });

//.print("completed").



//start and test CNP interaction
+!findhost(Ontology): true
	//query the last contract id to set N
	<-?last_host_contract_id(N);
	//increment N into a new variable ContractId
    ContractId = N + 1;
    //update the last_contract_id belief with the new value
    -+last_host_contract_id(ContractId);
   //example of using an internal action
   // ca.athabascau.quizmaster.internalactions.getsingleontology(O);
   // .print(O);
   // -+ontology(target_ontology,O);
    //initiate the negotiation with all introduced parties (contained in manager.asl)
	!startHostCNP(ContractId,testCNP(Ontology)).

//start and test CNP interaction
+!finduser: true
	//query the last contract id to set N
	<-?last_user_contract_id(N);
	//increment N into a new variable ContractId
    ContractId = N + 1;
    //update the last_contract_id belief with the new value
    -+last_user_contract_id(ContractId);
    ?ontology(target_ontology,Ont);
    ?plays(host,Host);
    //initiate the negotiation with all introduced parties (contained in manager.asl)
	!startUserCNP(ContractId,testCNP(Ont,Host)).


+testedCNP(_Ontology,_ContractId)[source(A)] : true 
  <-.print("Ontology ",_Ontology," has been received by:",A," as part of contract:",_ContractId).

+!announce_result(_,[],_).
// announce to the winner
+!announce_result(CNPId,[offer(_,WAg)|T],WAg) 
   <- .send(WAg,tell,accept_proposal(CNPId));
      !announce_result(CNPId,T,WAg).
	
// announce to others
+!announce_result(CNPId,[offer(_,LAg)|T],WAg) 
   <- .send(LAg,tell,reject_proposal(CNPId));
      !announce_result(CNPId,T,WAg).




//----------------------------------------------------User--------------------//
// start the CNP
+!startUserCNP(Id,Task) 
   <- .print("Waiting users...");
      .wait(2000);  // wait participants introduction
      +user_cnp_state(Id,propose);   // remember the state of the CNP
      .findall(Name,introduction(user,Name),LP);
      .print("Sending user CFP to ",LP);
      .send(LP,tell,cfp(Id,Task));
      // the deadline of the CNP is now + 4 seconds, so
      // the event +!contract(Id) is generated at that time
      .at("now +4 seconds", { +!user_contract(Id) }).

// receive proposal 
// if all proposal have been received, don't wait for the deadline
@umr1 +user_propose(CNPId,_Offer)
   :  user_cnp_state(CNPId,propose) & all_user_proposals_received(CNPId)
   <- !user_contract(CNPId).

// receive refusals   
@umr2 +user_refuse(CNPId) 
   :  user_cnp_state(CNPId,propose) & all_user_proposals_received(CNPId)
   <- !user_contract(CNPId).

// this plan needs to be atomic so as not to accept
// proposals or refusals while contracting
@ulc1[atomic]
+!user_contract(CNPId)
   :  user_cnp_state(CNPId,propose)
   <- -+user_cnp_state(CNPId,contract);
      .findall(offer(O,A),user_propose(CNPId,O)[source(A)],L);
      .print("Offers are ",L);
      L \== []; // constraint the plan execution to at least one offer
      .min(L,offer(WOf,WAg)); // sort offers, the first is the best
      .print("One of the users for user contract", CNPId ," is ",WAg," with ",WOf);
      
      !announce_result(CNPId,L,WAg);
     -+user_cnp_state(CNPId,finished).

// nothing todo, the current phase is not 'propose'
@ulc2 +!user_contract(_). 

-!user_contract(CNPId)
   <- .print("user contract ",CNPId," has failed!").

//+!announce_result(_,[],_).
// announce to the winner
//+!announce_result(CNPId,[offer(_,WAg)|T],WAg) 
//   <- .send(WAg,tell,accept_proposal(CNPId));
//      !announce_result(CNPId,T,WAg).
	
// announce to others
//+!announce_result(CNPId,[offer(_,LAg)|T],WAg) 
//   <- .send(LAg,tell,reject_proposal(CNPId));
//      !announce_result(CNPId,T,WAg).



 +user_completed_contract(CNPId)[source(A)]:user_count(0)
 <- .print("user",A," has reported that user contract ",CNPId," has been completed.");
 	?user_count(Count);
 	NewCount=Count+1;
 	-+user_count(NewCount);
 	.print("find another user");
  	+plays(user1,A);
  	!finduser.
 +user_completed_contract(CNPId)[source(A)]:user_count(1)
 <- .print("user",A," has reported that user contract ",CNPId," has been completed.");
 	-+user_count(0);
 	+plays(user2,A);
 	?last_host_contract_id(GameId);
  	.print("all users accounted for in game ",GameId);
  	?ontology(target_ontology,O);
  	!findhost(O).

 

  all_user_proposals_received(CNPId) 
  :- .count(introduction(user,_),NP) & // number of participants
     .count(propose(CNPId,_), NO) &   // number of proposes received
     .count(refuse(CNPId), NR) &     // number of refusals received
     NP = NO + NR.







//--------------------------------------Host specific------------------------------//
// start the CNP
+!startHostCNP(Id,Task) 
   <- .print("Waiting hosts...");
      .wait(2000);  // wait participants introduction
      +host_cnp_state(Id,propose);   // remember the state of the CNP
      .findall(Name,introduction(host,Name),LP);
      .print("Sending host contract CFP to ",LP);
      .send(LP,tell,cfp(Id,Task));
      // the deadline of the CNP is now + 4 seconds, so
      // the event +!contract(Id) is generated at that time
      .at("now +4 seconds", { +!host_contract(Id) }).

// receive proposal 
// if all proposal have been received, don't wait for the deadline
@hmr1 +host_propose(CNPId,_Offer)
   :  cnp_state(CNPId,propose) & all_host_proposals_received(CNPId)
   <- !host_contract(CNPId).

// receive refusals   
@hmr2 +host_refuse(CNPId) 
   :  host_cnp_state(CNPId,propose) & all_host_proposals_received(CNPId)
   <- !host_contract(CNPId).

// this plan needs to be atomic so as not to accept
// proposals or refusals while contracting
@hlc1[atomic]
+!host_contract(CNPId)
   :  host_cnp_state(CNPId,propose)
   <- -+host_cnp_state(CNPId,contract);
      .findall(offer(O,A),host_propose(CNPId,O)[source(A)],L);
      .print("Offers are ",L);
      L \== []; // constraint the plan execution to at least one offer
      .min(L,offer(WOf,WAg)); // sort offers, the first is the best
      .print("Host of host contract ", CNPID," is ",WAg," with ",WOf);
      !announce_result(CNPId,L,WAg);
      -+host_cnp_state(CNPId,finished).

// nothing todo, the current phase is not 'propose'
@hlc2 +!host_contract(_). 

-!host_contract(CNPId)
   <- .print("Host contract ",CNPId," has failed!").

//+!announce_result(_,[],_).
// announce to the winner
//+!announce_result(CNPId,[offer(_,WAg)|T],WAg) 
//   <- .send(WAg,tell,accept_proposal(CNPId));
//      !announce_result(CNPId,T,WAg).
	
// announce to others
//+!announce_result(CNPId,[offer(_,LAg)|T],WAg) 
//   <- .send(LAg,tell,reject_proposal(CNPId));
//      !announce_result(CNPId,T,WAg).



 +host_completed_contract(CNPId)[source(A)]:true
 <- .print(A," will play the host.");
 -+plays(host,A);
 !finduser.
 
   all_host_proposals_received(CNPId) 
  :- .count(introduction(host,_),NP) & // number of participants
     .count(propose(CNPId,_), NO) &   // number of proposes received
     .count(refuse(CNPId), NR) &     // number of refusals received
     NP = NO + NR.
 
 